package chat.client.statemachine.chat;

import java.util.Iterator;

import chat.State;
import chat.client.ChatClientState;
import chat.statemachine.AbstractContent;
import chat.statemachine.AlgorithmActionInvocationException;

/**
 * This class defines the methods implementing the reaction of the state machine
 * part concerning the reception of chat messages. Since only one message
 * content type is declared in the algorithm, there is only one state method in
 * this class.
 * 
 * @author Denis Conan
 * 
 */
public class AlgorithmChatActions {
	public static Object receiveChatMessageContent(final State state,
			final AbstractContent content)
	throws AlgorithmActionInvocationException {
		boolean changed = false;
		ChatClientState cstate = null;
		if (content == null) {
			throw new IllegalArgumentException(
					"Try executing action with null content");
		}
		if (state == null) {
			throw new IllegalArgumentException(
			"Try executing action with null state");
		}
		if (state instanceof ChatClientState) {
			cstate = (ChatClientState) state;
		} else {
			throw new IllegalArgumentException(
					"Try executing action with state of wrong type ("
					+ state.getClass().getName()
					+ " instead of ChatClientState");
		}
		if (content instanceof ChatMessageContent) {
			/* A message has been received */
			ChatMessageContent mymsg = (ChatMessageContent) content;
			//System.out.println(mymsg);
			try {
				cstate.semaphore.acquire();
			} catch (InterruptedException e) {
				System.out.println(e);
			}
			/* Add message to message bag */
			cstate.messageBag.add((ChatMessageContent) mymsg.clone());

			int p = cstate.identity;
			/* Identity of current thread */

			do {
				/*
				 * for (ChatMessageContent cmc : cstate.messageBag) {
				 * ConcurencyModification Error
				 */
				for (Iterator<ChatMessageContent> it = cstate.messageBag.listIterator(); it.hasNext();) {
					boolean deliver = false; 
					/* boolean used to tell if a message has to be delivered or not */
					ChatMessageContent cmc = it.next();
					int q = cmc.getSender();
					if (p == q) { 
						deliver = true; 
					}
					else if (cstate.localClock.isPrecededByAndFIFO(cmc.getVectorClock(), cmc.getSender())) {
						deliver = true;
					}
					if (deliver == true) {
						System.out.println(cmc.getContent());
						/* Boolean used to tell that we need to iterate
						 * another time on the messageBag 
						 */
						cstate.nbChatMessageContentReceived++;
						changed = true;
						
						/* Message is delivered, remove it from message bag */
						it.remove(); /* Optional */
						cstate.messageBag.remove(cmc);
					}
					else {
						changed = false;
					}
				}
			} while (changed);

			
			cstate.semaphore.release();
		} else {
			throw new AlgorithmActionInvocationException(
					"Error when executing action: not right message type ("
					+ content.getClass().getName() + ")");
		}
		return null;
	}
}
